TIP Swift Sample App/ZoomingTweetImageViewController.swift (152 lines of code) (raw):
//
// ZoomingTweetImageViewController.swift
// TwitterImagePipeline
//
// Created on 3/2/17.
// Copyright © 2020 Twitter. All rights reserved.
//
import TwitterImagePipeline
class ZoomingTweetImageViewController: UIViewController, UIScrollViewDelegate, TIPImageFetchDelegate {
var tweetImageInfo: TweetImageInfo?
private var scrollView: UIScrollView?
private var imageView: UIImageView?
private var progressView: UIProgressView?
private var doubleTapGestureRecognizer: UITapGestureRecognizer?
private var fetchOp: TIPImageFetchOperation?
init(tweetImage imageInfo:TweetImageInfo)
{
self.init()
self.tweetImageInfo = imageInfo
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
{
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.navigationItem.title = "Tweet Image"
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder)
{
fatalError("\(#function) has not been implemented")
}
override func viewDidLoad()
{
super.viewDidLoad()
var targetSize = self.tweetImageInfo!.originalDimensions
let scale = UIScreen.main.scale
targetSize.height /= scale
targetSize.width /= scale
self.progressView = UIProgressView.init(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 4.0))
self.progressView!.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
self.progressView!.tintColor = UIColor.yellow
self.progressView!.progress = 0
self.imageView = UIImageView.init(frame: CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height))
self.imageView!.contentMode = .scaleAspectFill
self.imageView!.clipsToBounds = true
self.imageView!.backgroundColor = UIColor.gray
self.scrollView = UIScrollView.init(frame: self.view.bounds)
self.scrollView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.scrollView!.backgroundColor = UIColor.black
let tapSelector: Selector = #selector(self.doubleTapTriggered(_:))
self.doubleTapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: tapSelector)
self.doubleTapGestureRecognizer!.numberOfTapsRequired = 2
self.imageView!.image = nil
self.imageView!.addGestureRecognizer(self.doubleTapGestureRecognizer!)
self.imageView!.isUserInteractionEnabled = true
self.scrollView!.delegate = self
self.scrollView!.minimumZoomScale = 0.01 // start VERY small
self.scrollView!.maximumZoomScale = 2.0
self.scrollView!.contentSize = targetSize
self.view!.addSubview(self.scrollView!)
self.view!.addSubview(self.progressView!)
self.scrollView!.addSubview(self.imageView!)
self.scrollView!.zoom(to: self.imageView!.frame, animated: false)
self.scrollView!.minimumZoomScale = self.scrollView!.zoomScale // readjust minimum
if (self.scrollView!.minimumZoomScale > self.scrollView!.maximumZoomScale) {
self.scrollView!.maximumZoomScale = self.scrollView!.minimumZoomScale
}
self.scrollViewDidZoom(self.scrollView!)
self.load()
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
self.scrollViewDidZoom(self.scrollView!)
var frame = self.progressView!.frame
frame.origin.y = self.scrollView!.contentInset.top
self.progressView!.frame = frame
}
// MARK: Double tap
@objc private func doubleTapTriggered(_ tapper: UITapGestureRecognizer)
{
if tapper.state == .recognized, let scrollView = self.scrollView {
if scrollView.zoomScale == scrollView.maximumZoomScale {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
} else {
scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)
}
}
}
// MARK: Scroll view delegate
func viewForZooming(in scrollView: UIScrollView) -> UIView?
{
return self.imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView)
{
let offsetX = max((scrollView.bounds.size.width - scrollView.contentInset.left - scrollView.contentInset.right - scrollView.contentSize.width) * 0.5, 0.0)
let offsetY = max((scrollView.bounds.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom - scrollView.contentSize.height) * 0.5, 0.0)
self.imageView?.center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX, y: scrollView.contentSize.height * 0.5 + offsetY)
}
// MARK: private
private func load()
{
let request = TweetImageFetchRequest.init(tweetImage: self.tweetImageInfo!, targetView: self.imageView!)
self.fetchOp = APP_DELEGATE().imagePipeline!.operation(with: request, context: nil, delegate: self)
APP_DELEGATE().imagePipeline!.fetchImage(with: self.fetchOp!)
}
// MARK: TIP delegate
func tip_imageFetchOperationDidStart(_ op: TIPImageFetchOperation)
{
print("starting Zoom fetch...")
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, willAttemptToLoadFrom source: TIPImageLoadSource)
{
print("...attempting load from next source: \(source)...")
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, didLoadPreviewImage previewResult: TIPImageFetchResult, completion: @escaping TIPImageFetchDidLoadPreviewCallback)
{
print("...preview loaded...")
self.progressView!.tintColor = UIColor.blue
self.imageView!.image = previewResult.imageContainer.image
completion(.continueLoading)
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, shouldLoadProgressivelyWithIdentifier identifier: String, url URL: URL, imageType: String, originalDimensions: CGSize) -> Bool
{
if nil != self.imageView?.image {
return false
}
return true
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, didUpdateProgressiveImage progressiveResult: TIPImageFetchResult, progress: Float)
{
print("...progressive update (\(progress))...")
self.progressView!.tintColor = UIColor.orange
self.progressView!.setProgress(progress, animated: true)
self.imageView!.image = progressiveResult.imageContainer.image
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, didLoadFirstAnimatedImageFrame progressiveResult: TIPImageFetchResult, progress: Float)
{
print("...animated first frame (\(progress))...")
self.progressView!.tintColor = UIColor.purple
self.progressView!.setProgress(progress, animated: true)
self.imageView!.image = progressiveResult.imageContainer.image
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, didUpdateProgress progress: Float)
{
print("...progress (\(progress))...")
self.progressView!.setProgress(progress, animated: true)
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, didLoadFinalImage finalResult: TIPImageFetchResult)
{
print("...completed zoom fetch")
self.progressView!.tintColor = UIColor.green
self.progressView!.setProgress(1.0, animated: true)
self.imageView!.image = finalResult.imageContainer.image
self.fetchOp = nil
}
func tip_imageFetchOperation(_ op: TIPImageFetchOperation, didFailToLoadFinalImage error: Error)
{
print("...failed zoom fetch: \(error)")
self.progressView!.tintColor = UIColor.red
self.fetchOp = nil
}
}